<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
  <head>

    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <meta content="Cask Data, Inc." name="author" />
<meta content="Copyright © 2014-2016 Cask Data, Inc." name="copyright" />


    <meta name="git_release" content="6.1.1">
    <meta name="git_hash" content="05fbac36f9f7aadeb44f5728cea35136dbc243e5">
    <meta name="git_timestamp" content="2020-02-09 08:22:47 +0800">
    <title>Analyzing CDAP Data from BI Tools</title>

    <link rel="stylesheet" href="../_static/cdap-bootstrap.css" type="text/css" />
    <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
    <link rel="stylesheet" href="../_static/bootstrap-3.3.6/css/bootstrap.min.css" type="text/css" />
    <link rel="stylesheet" href="../_static/bootstrap-3.3.6/css/bootstrap-theme.min.css" type="text/css" />
    <link rel="stylesheet" href="../_static/css/bootstrap-sphinx.css" type="text/css" />
    <link rel="stylesheet" href="../_static/css/cdap-dynamicscrollspy-4.css" type="text/css" />
    <link rel="stylesheet" href="../_static/css/jquery.mCustomScrollbar.css" type="text/css" />
    <link rel="stylesheet" href="../_static/css/cdap-jquery.mCustomScrollbar.css" type="text/css" />
    <link rel="stylesheet" href="../_static/css/abixTreeList-2.css" type="text/css" />
    <link rel="stylesheet" href="../_static/cdap-bootstrap.css" type="text/css" />

    <script type="text/javascript">
      var DOCUMENTATION_OPTIONS = {
        URL_ROOT:    '',
        VERSION:     '6.1.1',
        COLLAPSE_INDEX: false,
        FILE_SUFFIX: '.html',
        HAS_SOURCE:  false
      };
    </script>
    <script type="text/javascript" src="../_static/jquery.js"></script>
    <script type="text/javascript" src="../_static/underscore.js"></script>
    <script type="text/javascript" src="../_static/doctools.js"></script>
    <script type="text/javascript" src="../_static/language_data.js"></script>

    <link rel="shortcut icon" href="../_static/favicon.ico"/>
    <link rel="index" title="Index" href="../genindex.html" />
    <link rel="search" title="Search" href="../search.html" />
    <link rel="top" title="Cask Data Application Platform 6.1.1 Documentation" href="../index.html" />
    <link rel="up" title="How-To Guides" href="index.html" />
    <link rel="next" title="Data Analysis with OLAP Cube" href="cdap-cube-guide.html" />
    <link rel="prev" title="How-To Guides" href="index.html" />
    <!-- block extrahead -->
    <meta charset='utf-8'>
    <meta http-equiv='X-UA-Compatible' content='IE=edge,chrome=1'>
    <meta name='viewport' content='width=device-width, initial-scale=1.0, maximum-scale=1'>
    <meta name="apple-mobile-web-app-capable" content="yes">
    <!-- block extrahead end -->

</head>
<body role="document">

<!-- block navbar -->
<div id="navbar" class="navbar navbar-inverse navbar-default navbar-fixed-top">
    <div class="container-fluid">
      <div class="row">
        <div class="navbar-header">
          <!-- .btn-navbar is used as the toggle for collapsed navbar content -->
          <a class="navbar-brand" href="../table-of-contents/../../index.html">
            <span><img alt="CDAP logo" src="../_static/cdap_logo.svg"/></span>
          </a>

          <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".nav-collapse">
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
          </button>

          <div class="pull-right">
            <div class="dropdown version-dropdown">
              <a href="#" class="dropdown-toggle" data-toggle="dropdown"
                role="button" aria-haspopup="true" aria-expanded="false">
                v 6.1.1 <span class="caret"></span>
              </a>
              <ul class="dropdown-menu">
                <li><a href="//docs.cdap.io/cdap/5.1.2/en/index.html">v 5.1.2</a></li>
                <li><a href="//docs.cdap.io/cdap/4.3.4/en/index.html">v 4.3.4</a></li>
              </ul>
            </div>
          </div>
          <form class="navbar-form navbar-right navbar-search" action="../search.html" method="get">
            <div class="form-group">
              <div class="navbar-search-image material-icons"></div>
              <input type="text" name="q" class="form-control" placeholder="  Search" />
            </div>
            <input type="hidden" name="check_keywords" value="yes" />
            <input type="hidden" name="area" value="default" />
          </form>

          <div class="collapse navbar-collapse nav-collapse navbar-right navbar-navigation">
            <ul class="nav navbar-nav"><li class="docsite-nav-tab-container"><a class="docsite-nav-tab-link " href="../table-of-contents/../../index.html">简介</a></li><li class="docsite-nav-tab-container"><a class="docsite-nav-tab-link current" href="../table-of-contents/../../guides.html">手册</a></li><li class="docsite-nav-tab-container"><a class="docsite-nav-tab-link " href="../table-of-contents/../../reference-manual/index.html">参考</a></li><li class="docsite-nav-tab-container"><a class="docsite-nav-tab-link " href="../table-of-contents/../../faqs/index.html">帮助</a></li>
            </ul>
          </div>

        </div>
      </div>
    </div>
  </div><!-- block navbar end -->
<!-- block main content -->
<div class="main-container container">
  <div class="row"><div class="col-md-2">
      <div id="sidebar" class="bs-sidenav scrollable-y-outside" role="complementary">
<!-- theme_manual: examples-manual -->
<!-- theme_manual_highlight: guides -->
<!-- sidebar_title_link: ../table-of-contents/../../guides.html -->

  <div role="note" aria-label="manuals links"><h3><a href="../table-of-contents/../../guides.html">Guides</a></h3>

    <ul class="this-page-menu">
      <li class="toctree-l1"><a href="../table-of-contents/../../user-guide/index.html" rel="nofollow">用户手册</a>
      </li>
      <li class="toctree-l1"><a href="../table-of-contents/../../developer-manual/index.html" rel="nofollow">开发手册</a>
      </li>
      <li class="toctree-l1"><a href="../table-of-contents/../../admin-manual/index.html" rel="nofollow">管理手册</a>
      </li>
      <li class="toctree-l1"><a href="../table-of-contents/../../integrations/index.html" rel="nofollow">集成手册</a>
      </li>
      <li class="toctree-l1"><b><a href="../table-of-contents/../../examples-manual/index.html" rel="nofollow">最佳实践</a></b>
      <nav class="pagenav">
      <ul class="current">
<li class="toctree-l1"><a class="reference internal" href="../index.html">Introduction</a></li>
<li class="toctree-l1 current"><a class="reference internal" href="index.html">How-To Guides</a><ul class="current">
<li class="toctree-l2 current"><a class="current reference internal" href="#">Analyzing CDAP Data from BI Tools</a></li>
<li class="toctree-l2"><a class="reference internal" href="cdap-cube-guide.html">Data Analysis with OLAP Cube</a></li>
<li class="toctree-l2"><a class="reference internal" href="cdap-etl-guide.html">Creating Hydrator Applications using CDAP System Artifacts</a></li>
<li class="toctree-l2"><a class="reference internal" href="cdap-flow-guide.html">Real-Time Data Processing with a Flow</a></li>
<li class="toctree-l2"><a class="reference internal" href="cdap-flume-guide.html">Ingesting Data into CDAP using Apache Flume</a></li>
<li class="toctree-l2"><a class="reference internal" href="cdap-kafka-ingest-guide.html">Consuming Data from Kafka</a></li>
<li class="toctree-l2"><a class="reference internal" href="cdap-mapreduce-guide.html">Batch Data Processing with CDAP</a></li>
<li class="toctree-l2"><a class="reference internal" href="cdap-spark-guide.html">Iterative Data Processing with Apache Spark</a></li>
<li class="toctree-l2"><a class="reference internal" href="cdap-timeseries-guide.html">Storing Timeseries Data</a></li>
<li class="toctree-l2"><a class="reference internal" href="cdap-twitter-ingest-guide.html">Consuming Twitter Data in Real Time</a></li>
<li class="toctree-l2"><a class="reference internal" href="cdap-workflow-guide.html">Batch Data Processing with CDAP using Workflow</a></li>
</ul>
</li>
</ul>
</nav>
      </li>
    </ul>
  </div></div>
    </div><div class="col-md-8 content" id="main-content">
    
  <div class="section" id="analyzing-cdap-data-from-bi-tools">
<span id="cdap-bi-guide"></span><h1>Analyzing CDAP Data from BI Tools<a class="headerlink" href="#analyzing-cdap-data-from-bi-tools" title="Permalink to this headline">🔗</a></h1>
<blockquote class="pull-quote">
<div><strong>Source Code Repository:</strong> Source code (and other resources) for this guide are available at the
<a class="reference external" href="https://github.com/cdap-guides/cdap-bi-guide/tree/develop">CDAP Guides GitHub repository</a>.</div></blockquote>
<p>Cask Data Application Platform (CDAP) provides an abstraction—
<a class="reference external" href="http://docs.cdap.io/cdap/current/en/developers-manual/building-blocks/datasets/index.html">Datasets</a>
—to store data. In this guide, you will learn how
to integrate and analyze Datasets with BI (Business Intelligence) Tools.</p>
<div class="section" id="what-you-will-build">
<h2>What You Will Build<a class="headerlink" href="#what-you-will-build" title="Permalink to this headline">🔗</a></h2>
<p>This guide will take you through building a
<a class="reference external" href="http://docs.cdap.io/cdap/current/en/developers-manual/building-blocks/applications.html">CDAP application</a>
that processes purchase events from a
<a class="reference external" href="http://docs.cdap.io/cdap/current/en/developers-manual/building-blocks/streams.html">Stream</a>,
persists the results in a Dataset, and then analyzes them using a BI tool. You
will:</p>
<ul class="simple">
<li>build a CDAP Application that consumes purchase events from a Stream and stores them in a
<a class="reference external" href="http://docs.cdap.io/cdap/current/en/developers-manual/building-blocks/datasets/index.html">Dataset</a>;</li>
<li>build a
<a class="reference external" href="http://docs.cdap.io/cdap/current/en/developers-manual/building-blocks/flows-flowlets/flowlets.html">Flowlet</a>
that processes purchase events in realtime, writing the events into a Dataset; and</li>
<li>finally, access this Dataset from a BI tool to run queries by
joining purchase events in the Dataset with a product catalog—a
local data source in the BI tool.</li>
</ul>
</div>
<div class="section" id="what-you-will-need">
<h2>What You Will Need<a class="headerlink" href="#what-you-will-need" title="Permalink to this headline">🔗</a></h2>
<ul class="simple">
<li><a class="reference external" href="http://www.oracle.com/technetwork/java/javase/downloads/index.html">JDK 7 or 8</a></li>
<li><a class="reference external" href="http://maven.apache.org/">Apache Maven 3.1+</a></li>
<li><a class="reference external" href="http://docs.cdap.io/cdap/current/en/developers-manual/getting-started/standalone/index.html">CDAP SDK</a></li>
<li><a class="reference external" href="http://community.pentaho.com/">Pentaho Data Integration</a></li>
</ul>
</div>
<div class="section" id="lets-build-it">
<h2>Let’s Build It!<a class="headerlink" href="#lets-build-it" title="Permalink to this headline">🔗</a></h2>
<p>The following sections will guide you through building an application from scratch. If you
are interested in deploying and running the application right away, you can clone its
source code and binaries from this GitHub repository. In that case, feel free to skip the
next two sections and jump right to the
<a class="reference external" href="#build-and-run-application">Build and Run Application</a> section.</p>
<div class="section" id="application-design">
<h3>Application Design<a class="headerlink" href="#application-design" title="Permalink to this headline">🔗</a></h3>
<p>In this example, we will learn how to explore purchase events using the <em>Pentaho</em> BI
Tool. We can ask questions such as <em>“What is the total spend of a customer for a given day?”</em></p>
<a class="reference internal image-reference" href="../_images/app-design.png"><img alt="../_images/app-design.png" class="align-center" src="../_images/app-design.png" style="width: 8in;" /></a>
<p>A purchase event consists of:</p>
<ul class="simple">
<li>Customer</li>
<li>Quantity purchased</li>
<li>Product</li>
</ul>
<p>Purchase events are injected into the <code class="docutils literal notranslate"><span class="pre">purchases</span></code> Stream. The <code class="docutils literal notranslate"><span class="pre">sink</span></code> Flowlet
reads events from the Stream and writes them into the <code class="docutils literal notranslate"><span class="pre">PurchasesDataset</span></code>. The
<code class="docutils literal notranslate"><span class="pre">PurchasesDataset</span></code> has Hive integration enabled and can be queried,
like any regular Database table, from a BI tool by using the
<a class="reference external" href="http://docs.cdap.io/cdap/current/en/integrations/jdbc.html">CDAP JDBC Driver</a>.</p>
</div>
<div class="section" id="implementation">
<h3>Implementation<a class="headerlink" href="#implementation" title="Permalink to this headline">🔗</a></h3>
<p>The first step is to get our application structure set up. We will use a
standard Maven project structure for all of the source code files:</p>
<div class="highlight-console notranslate"><div class="highlight"><pre><span></span><span class="go">./pom.xml</span>
<span class="go">./src/main/java/co/cask/cdap/guides/purchase/Purchase.java</span>
<span class="go">./src/main/java/co/cask/cdap/guides/purchase/PurchaseApp.java</span>
<span class="go">./src/main/java/co/cask/cdap/guides/purchase/PurchaseFlow.java</span>
<span class="go">./src/main/java/co/cask/cdap/guides/purchase/PurchaseSinkFlowlet.java</span>
<span class="go">./src/main/java/co/cask/cdap/guides/purchase/PurchaseStore.java</span>
</pre></div>
</div>
<p>The application is identified by the <code class="docutils literal notranslate"><span class="pre">PurchaseApp</span></code> class. This class
extends <a class="reference external" href="http://docs.cdap.io/cdap/current/en/reference-manual/javadocs/co/cask/cdap/api/app/AbstractApplication.html">AbstractApplication</a>,
and overrides the <code class="docutils literal notranslate"><span class="pre">configure()</span></code> method to define all of the application components:</p>
<div class="highlight-java notranslate"><div class="highlight"><pre><span></span><span class="kd">public</span> <span class="kd">class</span> <span class="nc">PurchaseApp</span> <span class="kd">extends</span> <span class="n">AbstractApplication</span> <span class="p">{</span>

  <span class="kd">public</span> <span class="kd">static</span> <span class="kd">final</span> <span class="n">String</span> <span class="n">APP_NAME</span> <span class="o">=</span> <span class="s">&quot;PurchaseApp&quot;</span><span class="p">;</span>

  <span class="nd">@Override</span>
  <span class="kd">public</span> <span class="kt">void</span> <span class="nf">configure</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">setName</span><span class="p">(</span><span class="n">APP_NAME</span><span class="p">);</span>
    <span class="n">addStream</span><span class="p">(</span><span class="k">new</span> <span class="n">Stream</span><span class="p">(</span><span class="s">&quot;purchases&quot;</span><span class="p">));</span>
    <span class="n">addFlow</span><span class="p">(</span><span class="k">new</span> <span class="n">PurchaseFlow</span><span class="p">());</span>
    <span class="n">createDataset</span><span class="p">(</span><span class="s">&quot;PurchasesDataset&quot;</span><span class="p">,</span> <span class="n">PurchaseStore</span><span class="p">.</span><span class="na">class</span><span class="p">,</span> <span class="n">PurchaseStore</span><span class="p">.</span><span class="na">properties</span><span class="p">());</span>
  <span class="p">}</span>
<span class="p">}</span>
</pre></div>
</div>
<p>When it comes to handling time-based events, we need a place to receive
and process the events themselves. CDAP provides a real-time stream
processing system that is a great match for handling event streams. After first setting
the application name, our <code class="docutils literal notranslate"><span class="pre">PurchaseApp</span></code> adds a new Stream, called <code class="docutils literal notranslate"><span class="pre">purchases</span></code>.</p>
<p>We also need a place to store the purchase event records that we
receive; <code class="docutils literal notranslate"><span class="pre">PurchaseApp</span></code> next creates a Dataset to store the processed
data. <code class="docutils literal notranslate"><span class="pre">PurchaseApp</span></code> uses an <a class="reference external" href="http://docs.cdap.io/cdap/current/en/reference-manual/javadocs/co/cask/cdap/api/dataset/lib/ObjectStore.html">ObjectStore</a>
Dataset to store the purchase events. The purchase events are
represented as a Java class, <code class="docutils literal notranslate"><span class="pre">Purchase</span></code>:</p>
<div class="highlight-java notranslate"><div class="highlight"><pre><span></span><span class="kd">public</span> <span class="kd">class</span> <span class="nc">Purchase</span> <span class="p">{</span>
  <span class="kd">private</span> <span class="kd">final</span> <span class="n">String</span> <span class="n">customer</span><span class="p">;</span>
  <span class="kd">private</span> <span class="kd">final</span> <span class="n">String</span> <span class="n">product</span><span class="p">;</span>
  <span class="kd">private</span> <span class="kd">final</span> <span class="kt">int</span> <span class="n">quantity</span><span class="p">;</span>
  <span class="kd">private</span> <span class="kd">final</span> <span class="kt">long</span> <span class="n">purchaseTime</span><span class="p">;</span>

  <span class="kd">public</span> <span class="nf">Purchase</span><span class="p">(</span><span class="n">String</span> <span class="n">customer</span><span class="p">,</span> <span class="n">String</span> <span class="n">product</span><span class="p">,</span> <span class="kt">int</span> <span class="n">quantity</span><span class="p">,</span> <span class="kt">long</span> <span class="n">purchaseTime</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">this</span><span class="p">.</span><span class="na">customer</span> <span class="o">=</span> <span class="n">customer</span><span class="p">;</span>
    <span class="k">this</span><span class="p">.</span><span class="na">product</span> <span class="o">=</span> <span class="n">product</span><span class="p">;</span>
    <span class="k">this</span><span class="p">.</span><span class="na">quantity</span> <span class="o">=</span> <span class="n">quantity</span><span class="p">;</span>
    <span class="k">this</span><span class="p">.</span><span class="na">purchaseTime</span> <span class="o">=</span> <span class="n">purchaseTime</span><span class="p">;</span>
  <span class="p">}</span>

  <span class="kd">public</span> <span class="n">String</span> <span class="nf">getCustomer</span><span class="p">()</span> <span class="p">{</span>
    <span class="k">return</span> <span class="n">customer</span><span class="p">;</span>
  <span class="p">}</span>

  <span class="kd">public</span> <span class="kt">long</span> <span class="nf">getPurchaseTime</span><span class="p">()</span> <span class="p">{</span>
    <span class="k">return</span> <span class="n">purchaseTime</span><span class="p">;</span>
  <span class="p">}</span>

  <span class="kd">public</span> <span class="kt">int</span> <span class="nf">getQuantity</span><span class="p">()</span> <span class="p">{</span>
    <span class="k">return</span> <span class="n">quantity</span><span class="p">;</span>
  <span class="p">}</span>

  <span class="kd">public</span> <span class="n">String</span> <span class="nf">getProduct</span><span class="p">()</span> <span class="p">{</span>
    <span class="k">return</span> <span class="n">product</span><span class="p">;</span>
  <span class="p">}</span>

  <span class="kd">public</span> <span class="kt">byte</span><span class="o">[]</span> <span class="nf">getKey</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">String</span> <span class="n">hashedKey</span> <span class="o">=</span> <span class="n">purchaseTime</span> <span class="o">+</span> <span class="n">customer</span> <span class="o">+</span> <span class="n">product</span><span class="p">;</span>
    <span class="k">return</span> <span class="n">hashedKey</span><span class="p">.</span><span class="na">getBytes</span><span class="p">();</span>
  <span class="p">}</span>
<span class="p">}</span>
</pre></div>
</div>
<p>PurchaseApp adds a <code class="docutils literal notranslate"><span class="pre">PurchaseFlow</span></code> to process data from the Stream and
store it into the Dataset:</p>
<div class="highlight-java notranslate"><div class="highlight"><pre><span></span><span class="kd">public</span> <span class="kd">class</span> <span class="nc">PurchaseFlow</span> <span class="kd">extends</span> <span class="n">AbstractFlow</span> <span class="p">{</span>

  <span class="nd">@Override</span>
  <span class="kd">public</span> <span class="kt">void</span> <span class="nf">configure</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">setName</span><span class="p">(</span><span class="s">&quot;PurchaseFlow&quot;</span><span class="p">);</span>
    <span class="n">setDescription</span><span class="p">(</span><span class="s">&quot;Reads purchase events from a stream and stores the purchases in a Dataset&quot;</span><span class="p">);</span>
    <span class="n">addFlowlet</span><span class="p">(</span><span class="s">&quot;sink&quot;</span><span class="p">,</span> <span class="k">new</span> <span class="n">PurchaseSinkFlowlet</span><span class="p">());</span>
    <span class="n">connectStream</span><span class="p">(</span><span class="s">&quot;purchases&quot;</span><span class="p">,</span> <span class="s">&quot;sink&quot;</span><span class="p">);</span>
  <span class="p">}</span>
<span class="p">}</span>
</pre></div>
</div>
<p>The <code class="docutils literal notranslate"><span class="pre">PurchaseFlow</span></code> contains a <code class="docutils literal notranslate"><span class="pre">PurchaseSinkFlowlet</span></code> that writes to the Dataset:</p>
<div class="highlight-java notranslate"><div class="highlight"><pre><span></span><span class="kd">public</span> <span class="kd">class</span> <span class="nc">PurchaseSinkFlowlet</span> <span class="kd">extends</span> <span class="n">AbstractFlowlet</span> <span class="p">{</span>

  <span class="kd">private</span> <span class="kd">static</span> <span class="kd">final</span> <span class="n">Logger</span> <span class="n">LOG</span> <span class="o">=</span> <span class="n">LoggerFactory</span><span class="p">.</span><span class="na">getLogger</span><span class="p">(</span><span class="n">PurchaseSinkFlowlet</span><span class="p">.</span><span class="na">class</span><span class="p">);</span>

  <span class="nd">@UseDataSet</span><span class="p">(</span><span class="s">&quot;PurchasesDataset&quot;</span><span class="p">)</span>
  <span class="kd">private</span> <span class="n">PurchaseStore</span> <span class="n">store</span><span class="p">;</span>

  <span class="nd">@ProcessInput</span>
  <span class="kd">public</span> <span class="kt">void</span> <span class="nf">process</span><span class="p">(</span><span class="n">StreamEvent</span> <span class="n">event</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">String</span> <span class="n">body</span> <span class="o">=</span> <span class="n">Charsets</span><span class="p">.</span><span class="na">UTF_8</span><span class="p">.</span><span class="na">decode</span><span class="p">(</span><span class="n">event</span><span class="p">.</span><span class="na">getBody</span><span class="p">()).</span><span class="na">toString</span><span class="p">();</span>
    <span class="c1">// &lt;customer&gt;,&lt;quantity&gt;,&lt;productId&gt;</span>
    <span class="n">String</span><span class="o">[]</span> <span class="n">tokens</span> <span class="o">=</span>  <span class="n">body</span><span class="p">.</span><span class="na">split</span><span class="p">(</span><span class="s">&quot;,&quot;</span><span class="p">);</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">tokens</span><span class="p">.</span><span class="na">length</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
      <span class="n">tokens</span><span class="o">[</span><span class="n">i</span><span class="o">]</span> <span class="o">=</span> <span class="n">tokens</span><span class="o">[</span><span class="n">i</span><span class="o">]</span><span class="p">.</span><span class="na">trim</span><span class="p">();</span>
    <span class="p">}</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">tokens</span><span class="p">.</span><span class="na">length</span> <span class="o">!=</span> <span class="mi">3</span><span class="p">)</span> <span class="p">{</span>
      <span class="n">LOG</span><span class="p">.</span><span class="na">error</span><span class="p">(</span><span class="s">&quot;Invalid stream event:{}&quot;</span><span class="p">,</span> <span class="n">body</span><span class="p">);</span>
      <span class="k">return</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="n">String</span> <span class="n">customer</span> <span class="o">=</span> <span class="n">tokens</span><span class="o">[</span><span class="mi">0</span><span class="o">]</span><span class="p">;</span>
    <span class="kt">int</span> <span class="n">quantity</span> <span class="o">=</span> <span class="n">Integer</span><span class="p">.</span><span class="na">parseInt</span><span class="p">(</span><span class="n">tokens</span><span class="o">[</span><span class="mi">1</span><span class="o">]</span><span class="p">);</span>
    <span class="n">String</span> <span class="n">item</span> <span class="o">=</span> <span class="n">tokens</span><span class="o">[</span><span class="mi">2</span><span class="o">]</span><span class="p">;</span>

    <span class="n">Purchase</span> <span class="n">purchase</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Purchase</span><span class="p">(</span><span class="n">customer</span><span class="p">,</span> <span class="n">item</span><span class="p">,</span> <span class="n">quantity</span><span class="p">,</span> <span class="n">System</span><span class="p">.</span><span class="na">currentTimeMillis</span><span class="p">());</span>
    <span class="n">store</span><span class="p">.</span><span class="na">write</span><span class="p">(</span><span class="n">purchase</span><span class="p">);</span>
  <span class="p">}</span>
<span class="p">}</span>
</pre></div>
</div>
<p><code class="docutils literal notranslate"><span class="pre">PurchaseStore</span></code> is a custom dataset that implements the <code class="docutils literal notranslate"><span class="pre">RecordScannable</span></code> interface for
integration with Hive:</p>
<div class="highlight-java notranslate"><div class="highlight"><pre><span></span><span class="kd">public</span> <span class="kd">class</span> <span class="nc">PurchaseStore</span> <span class="kd">extends</span> <span class="n">AbstractDataset</span> <span class="kd">implements</span> <span class="n">RecordScannable</span><span class="o">&lt;</span><span class="n">Purchase</span><span class="o">&gt;</span> <span class="p">{</span>

  <span class="kd">private</span> <span class="kd">final</span> <span class="n">ObjectStore</span><span class="o">&lt;</span><span class="n">Purchase</span><span class="o">&gt;</span> <span class="n">store</span><span class="p">;</span>

  <span class="kd">public</span> <span class="kd">static</span> <span class="n">DatasetProperties</span> <span class="nf">properties</span><span class="p">()</span> <span class="p">{</span>
    <span class="k">try</span> <span class="p">{</span>
      <span class="k">return</span> <span class="n">ObjectStores</span><span class="p">.</span><span class="na">objectStoreProperties</span><span class="p">(</span><span class="n">Purchase</span><span class="p">.</span><span class="na">class</span><span class="p">,</span> <span class="n">DatasetProperties</span><span class="p">.</span><span class="na">EMPTY</span><span class="p">);</span>
    <span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="n">UnsupportedTypeException</span> <span class="n">e</span><span class="p">)</span> <span class="p">{</span>
      <span class="k">throw</span> <span class="k">new</span> <span class="n">RuntimeException</span><span class="p">(</span><span class="s">&quot;This should never be thrown - Purchase is a supported type&quot;</span><span class="p">,</span> <span class="n">e</span><span class="p">);</span>
    <span class="p">}</span>
  <span class="p">}</span>

  <span class="kd">public</span> <span class="nf">PurchaseStore</span><span class="p">(</span><span class="n">DatasetSpecification</span> <span class="n">spec</span><span class="p">,</span>
                       <span class="nd">@EmbeddedDataset</span><span class="p">(</span><span class="s">&quot;store&quot;</span><span class="p">)</span> <span class="n">ObjectStore</span><span class="o">&lt;</span><span class="n">Purchase</span><span class="o">&gt;</span> <span class="n">objStore</span><span class="p">)</span> <span class="p">{</span>
    <span class="kd">super</span><span class="p">(</span><span class="n">spec</span><span class="p">.</span><span class="na">getName</span><span class="p">(),</span> <span class="n">objStore</span><span class="p">);</span>
    <span class="k">this</span><span class="p">.</span><span class="na">store</span> <span class="o">=</span> <span class="n">objStore</span><span class="p">;</span>
  <span class="p">}</span>

  <span class="nd">@Override</span>
  <span class="kd">public</span> <span class="n">Type</span> <span class="nf">getRecordType</span><span class="p">()</span> <span class="p">{</span>
    <span class="k">return</span> <span class="n">Purchase</span><span class="p">.</span><span class="na">class</span><span class="p">;</span>
  <span class="p">}</span>

  <span class="nd">@Override</span>
  <span class="kd">public</span> <span class="n">List</span><span class="o">&lt;</span><span class="n">Split</span><span class="o">&gt;</span> <span class="nf">getSplits</span><span class="p">()</span> <span class="p">{</span>
    <span class="k">return</span> <span class="n">store</span><span class="p">.</span><span class="na">getSplits</span><span class="p">();</span>
  <span class="p">}</span>

  <span class="nd">@Override</span>
  <span class="kd">public</span> <span class="n">RecordScanner</span><span class="o">&lt;</span><span class="n">Purchase</span><span class="o">&gt;</span> <span class="nf">createSplitRecordScanner</span><span class="p">(</span><span class="n">Split</span> <span class="n">split</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">return</span> <span class="n">Scannables</span><span class="p">.</span><span class="na">valueRecordScanner</span><span class="p">(</span><span class="n">store</span><span class="p">.</span><span class="na">createSplitReader</span><span class="p">(</span><span class="n">split</span><span class="p">));</span>
  <span class="p">}</span>

  <span class="kd">public</span> <span class="kt">void</span> <span class="nf">write</span><span class="p">(</span><span class="n">Purchase</span> <span class="n">purchase</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">store</span><span class="p">.</span><span class="na">write</span><span class="p">(</span><span class="n">purchase</span><span class="p">.</span><span class="na">getKey</span><span class="p">(),</span> <span class="n">purchase</span><span class="p">);</span>
  <span class="p">}</span>

  <span class="kd">public</span> <span class="n">Purchase</span> <span class="nf">read</span><span class="p">(</span><span class="kt">byte</span><span class="o">[]</span> <span class="n">key</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">return</span> <span class="n">store</span><span class="p">.</span><span class="na">read</span><span class="p">(</span><span class="n">key</span><span class="p">);</span>
  <span class="p">}</span>
<span class="p">}</span>
</pre></div>
</div>
</div>
</div>
<div class="section" id="build-and-run-application">
<h2>Build and Run Application<a class="headerlink" href="#build-and-run-application" title="Permalink to this headline">🔗</a></h2>
<p>The <code class="docutils literal notranslate"><span class="pre">PurchaseApp</span></code> application can be built and packaged using the Apache Maven command
from the project directory:</p>
<div class="highlight-console notranslate"><div class="highlight"><pre><span></span><span class="gp">$</span> mvn clean package
</pre></div>
</div>
<p>Note that the remaining commands assume that the <code class="docutils literal notranslate"><span class="pre">cdap</span></code> script is
available on your PATH. If this is not the case, please add it:</p>
<div class="highlight-console notranslate"><div class="highlight"><pre><span></span><span class="gp">$</span> <span class="nb">export</span> <span class="nv">PATH</span><span class="o">=</span><span class="nv">$PATH</span>:&lt;CDAP home&gt;/bin
</pre></div>
</div>
<p>If you haven’t already started a standalone CDAP installation, start it with the command:</p>
<div class="highlight-console notranslate"><div class="highlight"><pre><span></span><span class="gp">$</span> cdap sdk start
</pre></div>
</div>
<p>We can then deploy the application to a running standalone CDAP installation:</p>
<div class="highlight-console notranslate"><div class="highlight"><pre><span></span><span class="gp">$</span> cdap cli load artifact target/cdap-bi-guide-&lt;version&gt;.jar
<span class="gp">$</span> cdap cli create app PurchaseApp cdap-bi-guide &lt;version&gt; user
<span class="gp">$</span> cdap cli start flow PurchaseApp.PurchaseFlow
</pre></div>
</div>
<p>Next, we will send some sample purchase events into the stream for
processing. The purchase event consists of a <code class="docutils literal notranslate"><span class="pre">customer</span> <span class="pre">name</span></code>, a
<code class="docutils literal notranslate"><span class="pre">quantity</span> <span class="pre">purchased</span></code> and a <code class="docutils literal notranslate"><span class="pre">product</span> <span class="pre">purchased</span></code>:</p>
<div class="highlight-console notranslate"><div class="highlight"><pre><span></span><span class="gp">$</span> cdap cli send stream purchases <span class="se">\&quot;</span>Tom,    <span class="m">5</span>,       pear<span class="se">\&quot;</span>
<span class="gp">$</span> cdap cli send stream purchases <span class="se">\&quot;</span>Alice, <span class="m">12</span>,      apple<span class="se">\&quot;</span>
<span class="gp">$</span> cdap cli send stream purchases <span class="se">\&quot;</span>Alice,  <span class="m">6</span>,     banana<span class="se">\&quot;</span>
<span class="gp">$</span> cdap cli send stream purchases <span class="se">\&quot;</span>Bob,    <span class="m">2</span>,     orange<span class="se">\&quot;</span>
<span class="gp">$</span> cdap cli send stream purchases <span class="se">\&quot;</span>Bob,    <span class="m">1</span>, watermelon<span class="se">\&quot;</span>
<span class="gp">$</span> cdap cli send stream purchases <span class="se">\&quot;</span>Bob,   <span class="m">10</span>,      apple<span class="se">\&quot;</span>
</pre></div>
</div>
<p>Now that purchase events have been ingested by CDAP, they can be
explored with a BI tool such as <em>Pentaho Data Integration</em>.</p>
<ol class="arabic">
<li><p class="first">Download <a class="reference external" href="http://community.pentaho.com/">Pentaho Data Integration</a>
and unzip it.</p>
</li>
<li><p class="first">Before opening the <em>Pentaho Data Integration</em> application, copy the
<code class="docutils literal notranslate"><span class="pre">&lt;CDAP</span> <span class="pre">home&gt;/lib/co.cask.cdap.cdap-explore-jdbc-&lt;version&gt;.jar</span></code> file
from the CDAP SDK to the <code class="docutils literal notranslate"><span class="pre">&lt;data-integration-dir&gt;/lib</span></code> directory.</p>
</li>
<li><p class="first">Run <em>Pentaho Data Integration</em> by invoking
<code class="docutils literal notranslate"><span class="pre">&lt;data-integration-dir&gt;/spoon.sh</span></code> from a terminal.</p>
</li>
<li><p class="first">Open <code class="docutils literal notranslate"><span class="pre">&lt;cdap-bi-guide-dir&gt;/resources/total_spend_per_user.ktr</span></code> using
<em>File</em> -&gt; <em>Open URL</em></p>
<p>This is a <em>Kettle Transformation</em> file exported from Pentaho Data
Integration. This file contains a transformation that calculates the
total spend of a customer based on the previous purchase events. The
transformation has several components or steps:</p>
<ul class="simple">
<li><em>CDAP Purchases Dataset</em> is a step which uses the <code class="docutils literal notranslate"><span class="pre">PurchasesDataset</span></code>
as an input source. It pulls all of the stored purchase events
from CDAP.</li>
<li>The <em>Product Catalog CSV</em> step is another source of data, which
pulls in a table from a locally defined csv file. This table
contains a mapping of product name to product price, so that we can
put a pricing on the purchase events.</li>
<li>The <em>Join Rows</em> step joins the two data sources on the <code class="docutils literal notranslate"><span class="pre">product</span></code>
column, hence adding price information to the purchase event.</li>
<li>We use the <em>Product Cost Calculator</em> step to multiply
<code class="docutils literal notranslate"><span class="pre">purchase.quantity</span></code> by <code class="docutils literal notranslate"><span class="pre">price</span></code> to get the total cost for the
purchase.</li>
<li>The <em>Sort on Customer</em> sorts all of the rows by customer so that
the next step can aggregate on price.</li>
<li>The <em>Aggregate by Customer</em> groups the rows by customer and
aggregates on the total cost per purchase. This results in a
table that is a mapping from customer name to a total amount
spent by that customer.</li>
</ul>
</li>
<li><p class="first">Double click on the CSV file input step, and change the filename to
point to <code class="docutils literal notranslate"><span class="pre">&lt;cdap-bi-guide-dir&gt;/resources/prices.csv</span></code>:</p>
<a class="reference internal image-reference" href="../_images/edit-csv-input-file.png"><img alt="../_images/edit-csv-input-file.png" class="align-center" src="../_images/edit-csv-input-file.png" style="width: 8in;" /></a>
</li>
<li><p class="first">To run this transformation, click <em>Action</em> -&gt; <em>Run</em> -&gt; <em>Launch</em>.</p>
</li>
<li><p class="first">Once the transformation has completed execution, click on the
<em>Aggregate by Customer</em> step, and then click on the <em>Preview Data</em>
tab at the bottom to view the total amount spent by each customer.</p>
<a class="reference internal image-reference" href="../_images/preview-data.png"><img alt="../_images/preview-data.png" class="align-center" src="../_images/preview-data.png" style="width: 8in;" /></a>
</li>
</ol>
<p>Congratulations! You have now learned how to analyze CDAP Datasets from
a BI tool. Please continue to experiment and extend this sample application.</p>
</div>
<div class="section" id="related-topics">
<h2>Related Topics<a class="headerlink" href="#related-topics" title="Permalink to this headline">🔗</a></h2>
<ul class="simple">
<li><a class="reference external" href="http://docs.cask.co/cdap/current/en/integrations/jdbc.html">Connecting to CDAP Datasets using the CDAP JDBC driver</a></li>
<li><a class="reference external" href="http://wiki.pentaho.com/display/EAI/Pentaho+Data+Integration+%28Kettle%29+Tutorial">Pentaho Data Integration (Kettle) Tutorial</a></li>
</ul>
</div>
<div class="section" id="extend-this-example">
<h2>Extend This Example<a class="headerlink" href="#extend-this-example" title="Permalink to this headline">🔗</a></h2>
<p>Now that you know how to integrate CDAP Datasets with BI Tools for data
analysis, you can ask questions such as:</p>
<ul class="simple">
<li>How much revenue does a particular product generate in a day?</li>
<li>What are the three most popular products?</li>
</ul>
<p>If you were to add a ZIP code to the initial purchase events, you can then ask
location-based questions such as:</p>
<ul class="simple">
<li>What are the popular products in any location?</li>
<li>Which locations have the highest revenue?</li>
</ul>
</div>
<div class="section" id="share-and-discuss">
<h2>Share and Discuss!<a class="headerlink" href="#share-and-discuss" title="Permalink to this headline">🔗</a></h2>
<p>Have a question? Discuss at the <a class="reference external" href="https://groups.google.com/forum/#!forum/cdap-user">CDAP User Mailing List</a>.</p>
</div>
<div class="section" id="license">
<h2>License<a class="headerlink" href="#license" title="Permalink to this headline">🔗</a></h2>
<p>Copyright © 2014-2017 Cask Data, Inc.</p>
<p>Licensed under the Apache License, Version 2.0 (the “License”); you may
not use this file except in compliance with the License. You may obtain
a copy of the License at</p>
<p><a class="reference external" href="http://www.apache.org/licenses/LICENSE-2.0">http://www.apache.org/licenses/LICENSE-2.0</a></p>
<p>Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an “AS IS” BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.</p>
</div>
</div>

</div>
    <div class="col-md-2">
      <div id="right-sidebar" class="bs-sidenav scrollable-y" role="complementary">
        <div id="localtoc-scrollspy">
        </div>
      </div>
    </div></div>
</div>
<!-- block main content end -->
<!-- block footer -->
<footer class="footer">
      <div class="container">
        <div class="row">
          <div class="col-md-2 footer-left"><a title="How-To Guides" href="index.html" />Previous</a></div>
          <div class="col-md-8 footer-center"><a class="footer-tab-link" href="../table-of-contents/../../reference-manual/licenses/index.html">Copyright</a> &copy; 2014-2020 Cask Data, Inc.&bull; <a class="footer-tab-link" href="//docs.cask.co/cdap/6.1.1/cdap-docs-6.1.1-web.zip" rel="nofollow">Download</a> an archive or
<a class="footer-tab-link" href="//docs.cask.co/cdap">switch the version</a> of the documentation
          </div>
          <div class="col-md-2 footer-right"><a title="Data Analysis with OLAP Cube" href="cdap-cube-guide.html" />Next</a></div>
        </div>
      </div>
    </footer>
<!-- block footer end -->
<script type="text/javascript" src="../_static/bootstrap-3.3.6/js/bootstrap.min.js"></script><script type="text/javascript" src="../_static/js/bootstrap-sphinx.js"></script><script type="text/javascript" src="../_static/js/abixTreeList-2.js"></script><script type="text/javascript" src="../_static/js/cdap-dynamicscrollspy-4.js"></script><script type="text/javascript" src="../_static/js/cdap-version-menu.js"></script><script type="text/javascript" src="../_static/js/copy-to-clipboard.js"></script><script type="text/javascript" src="../_static/js/jquery.mousewheel.min.js"></script><script type="text/javascript" src="../_static/js/jquery.mCustomScrollbar.js"></script><script type="text/javascript" src="../_static/js/js.cookie.js"></script><script type="text/javascript" src="../_static/js/tabbed-parsed-literal-0.2.js"></script><script type="text/javascript" src="../_static/js/cdap-onload-javascript.js"></script><script type="text/javascript" src="../_static/js/cdap-version-menu.js"></script>
    <script src="https://cdap.gitee.io/docs/cdap/json-versions.js"/></script>
  </body>
</html>